package top.csjss.hospital.service.impl;


import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import top.csjss.hospital.constants.HospitalConstants;
import top.csjss.hospital.entity.SysMenu;
import top.csjss.hospital.entity.SysRole;
import top.csjss.hospital.entity.SysUser;
import top.csjss.hospital.entity.SysUserExample;
import top.csjss.hospital.enums.HospitalExceptionEnums;
import top.csjss.hospital.exception.HospitalException;
import top.csjss.hospital.mapper.SysUserMapper;
import top.csjss.hospital.realm.HospitalRealm;
import top.csjss.hospital.service.SysRoleService;
import top.csjss.hospital.service.SysUserService;
import top.csjss.hospital.util.ExampleUtil;
import top.csjss.hospital.vo.SideVO;
import top.csjss.hospital.vo.UserRoleVO;

import java.util.*;

/**
 * @Author ztf
 * @Date 15:35 2021/10/15
 **/
@Service
public class SysUserServiceImpl implements SysUserService {

    private Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);

    /**
     * 默认密码
     */
    private final String INIT_PASSWORD = "123456789abc!";
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysRoleService sysRoleService;

    @Override
    public SysUser findByLoginName(String loginName) {
        SysUserExample example = new SysUserExample();
        SysUserExample.Criteria criteria = example.createCriteria();
        criteria.andLoginNameEqualTo(loginName);
        List<SysUser> sysUsers = sysUserMapper.selectByExample(example);
        if (sysUsers != null && sysUsers.size() == 1) {
            if (sysUsers.get(0).getAvailable() != 1) {
                log.info("【登录功能】用户已失效，请联系管理员！");
                throw new HospitalException(HospitalExceptionEnums.USER_AVAILABLE_ERROR);
            }
            return sysUsers.get(0);
        }
        return null;
    }

    @Override
    public List<SideVO> findMenuByUserId(Integer userId) {
        //根据userId查询菜单信息
        List<SysMenu> sysMenus = sysUserMapper.findByUserId(userId);
        //封装数据
        List<SideVO> result = new ArrayList<>();
        Map<Integer, SideVO> oneLevelMenu = new HashMap<>();
        //2.1 从sysMenuList筛选出所有parentId = 1的以及菜单，并且封装到List集合
        ListIterator<SysMenu> menuListIterator = sysMenus.listIterator();
        while (menuListIterator.hasNext()) {
            SysMenu sysMenu = menuListIterator.next();
            //一级菜单
            if (sysMenu.getParentId() == 1) {
                SideVO vo = new SideVO();
                BeanUtils.copyProperties(sysMenu, vo);
                oneLevelMenu.put(vo.getId(), vo);
                menuListIterator.remove();
            }
        }
        //2.2 从sysMenuList中找到二级菜单，并且将二级菜单封装到指定的一级菜单的children属性中
        for (SysMenu sysMenu : sysMenus) {
            SideVO parentSideVo = oneLevelMenu.get(sysMenu.getParentId());
            if (parentSideVo != null) {
                //找到二级菜单指定的一级菜单
                SideVO childrenSideVO = new SideVO();
                BeanUtils.copyProperties(sysMenu, childrenSideVO);
                parentSideVo.getChildren().add(childrenSideVO);
            }
        }
        //2.3 将Map集合中的数据，都封装到result的list集合中
        for (Map.Entry<Integer, SideVO> integerSideVOEntry : oneLevelMenu.entrySet()) {
            result.add(integerSideVOEntry.getValue());
        }
        return result;
    }

    @Override
    public PageInfo<SysUser> selectAllUser(String realname, String loginname, String address, String identity, String phone, Integer page, Integer limit) {
        PageHelper.startPage(page, limit);
        //封装
        SysUserExample example = new SysUserExample();
        SysUserExample.Criteria criteria = example.createCriteria();
        //真实姓名
        if (!StringUtils.isEmpty(realname)) {
            criteria.andRealNameLike(ExampleUtil.any(realname));
        }
        //登录名
        if (!StringUtils.isEmpty(loginname)) {
            criteria.andRealNameLike(ExampleUtil.any(loginname));
        }
        if (!StringUtils.isEmpty(address)) {
            criteria.andRealNameLike(ExampleUtil.any(address));
        }
        if (!StringUtils.isEmpty(identity)) {
            criteria.andRealNameLike(ExampleUtil.any(identity));
        }
        if (!StringUtils.isEmpty(phone)) {
            criteria.andRealNameLike(ExampleUtil.any(phone));
        }
        //执行查询
        List<SysUser> list = sysUserMapper.selectByExample(example);
        //封装pageInfo
        PageInfo<SysUser> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void addUser(SysUser sysUser) {
        //封装数据pwd,salt,type(默认值2，系统用户)
        //1.1生成盐
        String salt = UUID.randomUUID().toString();
        //生成密码
        String pwd = new Md5Hash(INIT_PASSWORD, salt, HospitalRealm.HASH_ITERATIONS).toString();
        //生成用户类型
        Integer type = HospitalConstants.USER_TYPE_SYSTEM;
        //设置到sysUser中
        sysUser.setSalt(salt);
        sysUser.setPwd(pwd);
        sysUser.setType(type);
        //执行添加
        int count = sysUserMapper.insertSelective(sysUser);

        //健壮性判断
        if (count != 1) {
            log.error("【添加用户信息】 添加失败！sysUser = {}", sysUser);
            throw new HospitalException(HospitalExceptionEnums.USER_ADD_ERROR);
        }
    }

    @Override
    public List<UserRoleVO> initUserRole(Integer userid) {
        //查询全部角色信息
        List<SysRole> sysRoleList = sysRoleService.findAll();
        //查询当前角色拥有的角色id
        List<Integer> userRoleId = sysUserMapper.findUserRoleIdByUserId(userid);
        //封装UserRoleVO
        List<UserRoleVO> data = new ArrayList<>();
        for (SysRole sysRole : sysRoleList) {
            UserRoleVO vo = new UserRoleVO();
            BeanUtils.copyProperties(sysRole, vo);
            if (userRoleId.contains(vo.getRoleId())) {
                vo.setLayChecked(true);
            }
            data.add(vo);
        }
        return data;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveUserRole(Integer userid, Integer[] ids) {
        //先删除
        sysUserMapper.deleteByPrimaryKey(userid);
        //添加
        if (ids != null && ids.length > 0) {
            int count = sysUserMapper.saveUserRole(userid, ids);
            if (count != ids.length) {
                log.error("【分配角色信息】 分配角色信息失败 userId={},roleId={}", userid, Arrays.toString(ids));
                throw new HospitalException(HospitalExceptionEnums.USER_SAVE_USER_ROLE_ERROR);
            }
        }
    }


    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void updataUser(SysUser sysUser) {
        int count = sysUserMapper.updateByPrimaryKeySelective(sysUser);

        if (count != 1) {
            log.error("【修改用户信息】 修改失败！sysUser = {}", sysUser);
            throw new HospitalException(HospitalExceptionEnums.USER_UPDATA_ERROR);
        }

    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void resetUserPwd(Integer userid) {
        //根据id查询获取盐
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(userid);

        //根据盐生成默认密码
        String pwd = new Md5Hash(INIT_PASSWORD, sysUser.getSalt(), HospitalRealm.HASH_ITERATIONS).toString();
        sysUser.setPwd(pwd);
        SysUserExample example = new SysUserExample();
        SysUserExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(sysUser.getUserId());
        int count= sysUserMapper.updateByExample(sysUser, example);
        if (count != 1) {
            log.error("【重置密码】 修改失败！sysUser = {}", sysUser);
            throw new HospitalException(HospitalExceptionEnums.USER_RESET_PASSWORD_ERROR);
        }


    }

    @Override
    public void deleteUserByUserId(Integer userid) {
        //根据id查询用户
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(userid);
        //修改用户状态
        sysUser.setAvailable(0);
        int count = sysUserMapper.updateByPrimaryKeySelective(sysUser);
        if (count != 1) {
            log.error("【删除用户】 删除失败！sysUser = {}", sysUser);
            throw new HospitalException(HospitalExceptionEnums.USER_DELETE_ERROR);
        }
    }


}
